package cn.dglydrpy.study.common.websocket;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.atomic.AtomicInteger;

@Component
@ServerEndpoint("/websocket/{userId}") //访问URL  userId:客户端用户id
@Slf4j
@EqualsAndHashCode
public class WebSocketServer {

    //websocket是多例  使用静态注入
//    private static IChatService chatService;
//    @Autowired
//    public void setChatService(IChatService chatService){
//        WebSocketServer.chatService = chatService;
//    }
//
//    private static IWeixinUserService weixinUserService;
//    @Autowired
//    public void setWeixinUserService(IWeixinUserService weixinUserService){
//        WebSocketServer.weixinUserService = weixinUserService;
//    }

//    private static WeixinMpTemplateMsgService weixinMpTemplateMsgService;
//    @Autowired
//    public void setWeixinMpTemplateMsgService(WeixinMpTemplateMsgService weixinMpTemplateMsgService){
//        WebSocketServer.weixinMpTemplateMsgService = weixinMpTemplateMsgService;
//    }

    //静态变量，用来记录当前在线连接数
    private static volatile AtomicInteger onlineCount = new AtomicInteger(0);

    //与某个客户端的连接会话,需要通过它来给客户端发送数据
    private Session session;
    private String userId;

    //存放每个客户端对应的webSocketService对象
    private static CopyOnWriteArraySet<WebSocketServer> webSockets = new CopyOnWriteArraySet<>();
    //存放每个客户端对应的Session对象
    private static Map<String,Session> sessionPool = new ConcurrentHashMap<>();

    /**
     * 客户端连接成功调用的方法
     * @param session
     * @param userId
     */
    @OnOpen
    public void onOpen(Session session, @PathParam(value="userId")String userId) {
        //拿到和客户端建立的会话
        this.session = session;
        //将和该客户交互的WebSocketServer加入set中
        webSockets.add(this);
        //在线数加1
        addOnlineCount();
        //将和该客户交互的WebSocketServer加入map中
        sessionPool.put(userId, session);
        this.userId = userId;
//        log.info("【websocket消息】用户"+userId+"连接成功，当前在线总数为:"+ getOnlineCount());
    }

    /**
     * 客户端连接关闭调用的方法
     */
    @OnClose
    public void onClose() {
        //从set中删除
        webSockets.remove(this);
        //在线数减1
        subOnlineCount();
//        log.info("【websocket消息】用户"+this.userId+"连接断开，当前在线总数为:"+ getOnlineCount());
    }

    /**
     * 收到客户端消息调用的方法
     * @param message
     * @param session
     */
    @OnMessage
    public void onMessage(String message, Session session) {
//        log.info("【websocket消息】收到来自用户"+this.userId+"的消息:"+ message);
        JSONObject jsonObject= JSON.parseObject(message);
        //TODO
    }

    /**
     * 服务端发送广播消息
     */
    public void sendAllMessage(String message) {
//        log.info("【websocket消息】广播消息:"+message);
        for(WebSocketServer webSocket : webSockets) {
            try {
                webSocket.session.getAsyncRemote().sendText(message);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    /**
     * 服务端发送单点消息
     * @param userId
     * @param message  json字符串
     * @return true:发送成功  false:发送失败
     */
    public boolean sendOneMessage(String userId, String message) {
        Session session = sessionPool.get(userId);
        if (session != null) {
            try {
                synchronized (session){
                    //session.getAsyncRemote().sendText(message); //异步
                    session.getBasicRemote().sendText(message);   //同步
                }
                return true;
            } catch (Exception e) {
                e.printStackTrace();
            }
            return false;
        }else{
//            log.info("【websocket消息】未取到接收用户:"+userId+"的session信息不存在,消息发送失败!!!");
            return false;
        }
    }

    /**
     * 判断某个用户在否在线
     * @param userId
     * @return  true:在线  false:离线
     */
    public static boolean isKeepLiving(String userId){
        boolean flag = false;
        for (WebSocketServer webSocket : webSockets) {
           if(webSocket.session == sessionPool.get(userId)){
               flag = true;
               break;
           }
        }
        return flag;
    }

    /**
     * 异常处理
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error) {
//        log.error("【websocket消息】发生错误");
        error.printStackTrace();
    }
    /**
     * 实现服务器主动推送
     */
    public void sendMessage(String message) throws IOException {
        this.session.getBasicRemote().sendText(message);
    }

    /**
     * 群发自定义消息
     * */
    public static void sendInfo(String message,@PathParam("userId") String userId) throws IOException {
//        log.info("【websocket消息】推送消息到用户"+userId+"，推送内容:"+message);
        for (WebSocketServer item : webSockets) {
            try {
                //这里可以设定只推送给这个userId的，为null则全部推送
                if(userId == null) {
                    item.sendMessage(message);
                }else if(item.userId.equals(userId)){
                    item.sendMessage(message);
                }
            } catch (IOException e) {
                continue;
            }
        }
    }

    /**
     * 获取在线客户端的数量
     * @return
     */
    private static int getOnlineCount() {
        return onlineCount.get();
    }

    /**
     * 在线客户端的数量加1
     */
    private static void addOnlineCount() {
        onlineCount.incrementAndGet();
    }

    /**
     * 在线客户端的数量减1
     */
    private static void subOnlineCount() {
        onlineCount.decrementAndGet();
    }
}
